#!/usr/bin/env ruby

# Copyright (c) 2010-2012 Microsoft Corp.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#	http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

require 'rubygems'
require 'ruby-aws'
require 'certified'

module Amazon
module WebServices

class MechanicalTurkRequester

################
# Qualifications
################
def collect_qualification_requests(qual_id)
	request_list = []

	page_number = 1;
	begin
		r = self.GetQualificationRequests(	:QualificationTypeId => qual_id,
							:PageSize   => 100,
							:PageNumber => page_number )
		num_results = r[:GetQualificationRequestsResult][:NumResults]
		page_number = page_number + 1;

		if r[:GetQualificationRequestsResult].has_key?(:QualificationRequest)
			hit_obj = r[:GetQualificationRequestsResult][:QualificationRequest]
			case hit_obj
				when Array
					request_list.concat(hit_obj)
				when Hash
					request_list << hit_obj
			end
		end
	end until num_results == 0

	request_list
end

def collect_granted_qualifications(qual_id)
	qualification_list = []

	page_number = 1;
	begin
		r = self.GetQualificationsForQualificationType(	:QualificationTypeId => qual_id,
								:Status => 'Granted',
								:PageSize   => 100,
								:PageNumber => page_number )
		num_results = r[:GetQualificationsForQualificationTypeResult][:NumResults]
		page_number = page_number + 1;

		if r[:GetQualificationsForQualificationTypeResult].has_key?(:Qualification)
			hit_obj = r[:GetQualificationsForQualificationTypeResult][:Qualification]
			case hit_obj
				when Array
					qualification_list.concat(hit_obj)
				when Hash
					qualification_list << hit_obj
			end
		end
	end until num_results == 0

	qualification_list
end

def grant_qualification_request(qual_req_id, value)
	self.GrantQualification(	:QualificationRequestId => qual_req_id,
					:IntegerValue => value )
end

def reject_qualification_request(qual_req_id, message)
	self.RejectQualificationRequest(	:QualificationRequestId => qual_req_id,
						:Reason => message )
end

def activate_qualification_type(qual_id)
	r = self.UpdateQualificationType(       :QualificationTypeId => qual_id,
						:QualificationTypeStatus => "Active" );
end

def dispose_qualification_type(qual_id)
	r = self.UpdateQualificationType(       :QualificationTypeId => qual_id,
						:QualificationTypeStatus => "Inactive" );
end

def create_qualification_type(qual_name, description, question, answer)
	r = self.CreateQualificationType( :Name => qual_name,
					  :Description => description,
					  :RetryDelayInSeconds => 1,
					  :Test => question,
					  :TestDurationInSeconds => 3600*24,
					  :AnswerKey => answer,
					  :QualificationTypeStatus => "Active",
					  :AutoGranted => false)
	r[:QualificationType]
end

def update_qualification_type(qual_id, description, question, answer)
	r = self.UpdateQualificationType( :QualificationTypeId => qual_id,
					  :Description => description,
					  :RetryDelayInSeconds => 1,
					  :Test => question,
					  :TestDurationInSeconds => 3600*24,
					  :AnswerKey => answer,
					  :QualificationTypeStatus => "Active",
					  :AutoGranted => false)
	r[:QualificationType]
end

=begin
# as it is, this function is buggy, since the search by name may not return a unique result
def get_qualification_type_id_by_name(query)
	r = self.SearchQualificationTypes(	:MustBeRequestable => false,
			 			:MustBeOwnedByCaller => true,
		  				:Query => query	 )

	if r[:SearchQualificationTypesResult][:TotalNumResults].to_i == 0
		return ''
	else
		qual_type = r[:SearchQualificationTypesResult][:QualificationType]
		case qual_type
			when Array
				return qual_type[0][:QualificationTypeId]
			when Hash
				return qual_type[:QualificationTypeId]
		end
	end
end
=end

def assign_qualification(qual_id, worker_id, qual_value)
	r = self.assignQualification(   	:QualificationTypeId => qual_id,
						:WorkerId => worker_id,
						:IntegerValue => qual_value,
		       				:SendNotification => false )
end

def update_qualification(qual_id, worker_id, qual_value)
	r = self.updateQualificationScore(      :QualificationTypeId => qual_id,
						:SubjectId => worker_id,
						:IntegerValue => qual_value )
end

def revoke_qualification(qual_id, worker_id, message = nil)
	if message == nil
		r = self.revokeQualification(	:QualificationTypeId => qual_id,
						:SubjectId => worker_id	)
	else
		r = self.revokeQualification(	:QualificationTypeId => qual_id,
						:SubjectId => worker_id,
						:Reason => message )
	end
end

#############
# Assignments
#############
def collect_reviewable_HITs()
	hit_list = []

	page_number = 1;
	begin
		r = self.GetReviewableHITs(	:PageSize   => 100,
						:PageNumber => page_number )
		num_results = r[:GetReviewableHITsResult][:NumResults]
		page_number = page_number + 1;

		if r[:GetReviewableHITsResult].has_key?(:HIT)
			hit_obj = r[:GetReviewableHITsResult][:HIT]
			case hit_obj
				when Array
					hit_list.concat(hit_obj)
				when Hash
					hit_list << hit_obj
			end
		end
	end until num_results == 0

	hit_list
end

def collect_assignments_from_HITId(hit_id)
	assignment_list = []

	page_number = 1;
	begin
		r = self.GetAssignmentsForHIT(  :HITId      => hit_id,
						:PageSize   => 100,
						:PageNumber => page_number )
		num_results = r[:GetAssignmentsForHITResult][:NumResults]
		page_number = page_number + 1;

		if r[:GetAssignmentsForHITResult].has_key?(:Assignment)
			assignment_obj = r[:GetAssignmentsForHITResult][:Assignment]
			case assignment_obj
				when Array
					assignment_list.concat(assignment_obj)
				when Hash
					assignment_list << assignment_obj
			end
		end
	end until num_results == 0

	assignment_list
end

def approve_assignment(assignment_id, message)
	self.ApproveAssignment(  :AssignmentId => assignment_id,
				 :RequesterFeedback => message )
end

def reject_assignment(assignment_id, message)
	self.RejectAssignment(  :AssignmentId => assignment_id,
				:RequesterFeedback => message )
end

######
# HITs
######
def collect_HITs()
	hit_list = []

	page_number = 1;
	begin
		r = self.SearchHITs(	:PageSize   => 100,
					:PageNumber => page_number )
		num_results = r[:SearchHITsResult][:NumResults]
		page_number = page_number + 1;

		if r[:SearchHITsResult].has_key?(:HIT)
			hit_obj = r[:SearchHITsResult][:HIT]
			case hit_obj
				when Array
					hit_list.concat(hit_obj)
				when Hash
					hit_list << hit_obj
			end
		end
	end until num_results == 0

	hit_list
end

#####################
# Workers and Bonuses
#####################
def block_worker(worker_id, note)
	self.BlockWorker(	:WorkerId => worker_id,
				:Reason => note )
end

def unblock_worker(worker_id, note)
	self.UnblockWorker(	:WorkerId => worker_id,
				:Reason => note )
end

def email_workers(worker_ids, subject, body)
	self.NotifyWorkers(	:WorkerId    => worker_ids,
				:Subject     => subject,
				:MessageText => body )
end

def grant_bonus(worker_id, assignment_id, amount, message)
	price_data = { :Amount => amount, :CurrencyCode => 'USD' }
	self.GrantBonus(	:WorkerId => worker_id,
				:AssignmentId => assignment_id,
				:BonusAmount => price_data,
				:Reason => message )
end

end # MechanicalTurkRequester

end # Amazon::WebServices
end # Amazon

